home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
boot
/
netBoot.new
/
tftp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-19
|
12KB
|
442 lines
/*
* tftp.c
*
* @(#)tftp.c 1.9 88/02/08 Copyr 1986 Sun Micro
* Copyright (c) 1986 by Sun Microsystems, Inc.
*
* Standalone network boot via TFTP
*/
#ifdef sun4
#define SUN4
#endif
#ifdef sun3
#define SUN3
#endif
#include "machparam.h"
#include "boot.h"
#include "saio.h"
#include "socket.h"
#include "if.h"
#include "in.h"
#include "if_ether.h"
#include "in_systm.h"
#include "ip.h"
#include "udp.h"
#include "sainet.h"
#include "sunromvec.h"
#include "cpu.addrs.h"
#include <sys/exec.h>
#undef DEV_BSIZE
#undef MAX
#include "tftp.h"
#ifdef notdef
#include "globram.h"
#endif
#ifdef notdef
#define millitime() (gp->g_nmiclock)
#else
#define millitime() (*romp->v_nmiclock)
#endif
/* tftp error messages */
char *tftp_errs[] = {
"not defined",
"file not found",
"access violation",
"disk full or allocation exceeded",
"illegal TFTP operation",
"unknown transfer ID",
"file already exists",
"no such user"
};
/* TFTP packet */
struct tftp_pack {
/* struct ether_header tf_ether; */ /* Ethernet header */
struct ip tf_ip; /* IP header */
struct udphdr tf_udp; /* UDP header */
struct tftphdr tf_tftp; /* TFTP header */
char tftp_data[SEGSIZE]; /* TFTP data beyond header */
};
/*
* Size of Headers in TFTP DATA packet
*/
#define TFTPHDRLEN (sizeof (struct ether_header) + sizeof (struct ip) + \
sizeof (struct udphdr) + 4)
struct tftpglob {
struct tftp_pack tf_out; /* outgoing TFTP packet */
struct sainet tf_inet; /* Internet state */
struct ether_header in_etherheader;
char tf_tmpbuf[1600]; /* tmp for incoming packets */
int tf_block; /* current block number */
char *tf_data; /* current load pointer */
};
#if defined(SUN4) && defined(CACHE) /* for loading into cache */
#define LOADADDR 0x20000
#define TFTPBASE ((struct tftpglob *) 0xFFDC0300)
#else CACHE
#define LOADADDR 0x4000
#define TFTPBASE ((struct tftpglob *)0x3000)
#endif SUN4 && CACHE
#define REXMIT_MSEC 4000 /* 4 seconds between retransmits */
/*
* Description: Entry point for initializing the ethernet during boot.
*
* Synopsis: status = etheropen(sip)
* status :(int) 0 command complete
* sip :(char *) pointer to saioreq structure
*
* Routines: bzero, inet_init
*/
etheropen(sip)
register struct saioreq *sip;
{
register struct tftpglob *tf = TFTPBASE;
bzero((caddr_t)tf, sizeof(*tf)); /* clear tftp work space */
inet_init(sip, &tf->tf_inet, tf->tf_tmpbuf); /* get internet address */
return (0);
}
#ifdef SUN2
etherstrategy(sip, rw)
register struct saioreq *sip;
int rw;
{
printf("tftp: random access attempted - code error.\n");
return(-1);
}
#endif SUN2
/*
* Description: Loads the boot routine across the ethernet
*
* Synopsis: status = tftpload(sip)
* status :(int) load address
* -1 error
* sip :(char *) pointer to saioreq structure
*
* Routines: bzero
*
* Variables: locked :(int) lock in host and server
* firsttry:(int) first try flag for autoboot
*/
tftpload(sip, bp)
register struct saioreq *sip;
struct bootparam *bp ;
{
register struct tftpglob *tf = TFTPBASE;
register struct tftp_pack *out = &tf->tf_out;
register struct tftp_pack *in = (struct tftp_pack *)tf->tf_tmpbuf;
register char *p, *q, *x;
register short i, len;
int autoboot = 0;
int firsttry = 0;
int feedback = 0;
int finished = 0;
int delay = REXMIT_MSEC;
int time, xcount, locked, retry;
char *ind = "-=-=";
#ifdef SUN4
u_long temp=0;
#endif SUN4
struct exec *header;
/* if unit # is 0, this is
* an autoboot */
if (sip->si_unit == 0)
autoboot = 1;
top:
/* Initialize IP header */
out->tf_ip.ip_v = IPVERSION; /* IP version number */
out->tf_ip.ip_hl = sizeof(struct ip) / 4;/* header length */
out->tf_ip.ip_ttl = MAXTTL; /* time to live */
out->tf_ip.ip_p = IPPROTO_UDP; /* type of protocol */
/* set source address */
bcopy(&tf->tf_inet.sain_myaddr, &out->tf_ip.ip_src, sizeof(out->tf_ip.ip_src));
/* set destination address,
* Dst host is argument with
* our net number plugged in */
if (autoboot && firsttry == 0) {
/* send to host from revarp */
#ifdef SUN4
out->tf_ip.ip_dst.S_un.S_un_b.s_b1=
tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b1;
out->tf_ip.ip_dst.S_un.S_un_b.s_b2=
tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b2;
out->tf_ip.ip_dst.S_un.S_un_b.s_b3=
tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b3;
out->tf_ip.ip_dst.S_un.S_un_b.s_b4=
tf->tf_inet.sain_hisaddr.S_un.S_un_b.s_b4;
#else SUN4
out->tf_ip.ip_dst.s_addr = tf->tf_inet.sain_hisaddr.s_addr;
#endif SUN4
firsttry = 1;
} else if (autoboot && firsttry > 0) {
/* broadcast? */
#ifdef SUN4
out->tf_ip.ip_dst.S_un.S_un_b.s_b1=(-1);
out->tf_ip.ip_dst.S_un.S_un_b.s_b2=(-1);
out->tf_ip.ip_dst.S_un.S_un_b.s_b3=(-1);
out->tf_ip.ip_dst.S_un.S_un_b.s_b4=(-1);
#else SUN4
out->tf_ip.ip_dst.s_addr = -1;
#endif SUN4
} else {
/* unit specified */
#ifdef SUN4
struct in_addr in;
bcopy(&out->tf_ip.ip_src.s_addr, &in, sizeof(in));
temp = in.s_addr;
temp -= in_lnaof(in);
temp += sip->si_unit;
bcopy(&temp, &out->tf_ip.ip_dst.s_addr, sizeof(temp));
#else SUN4
out->tf_ip.ip_dst.s_addr = out->tf_ip.ip_src.s_addr +
sip->si_unit - in_lnaof(out->tf_ip.ip_src);
#endif SUN4
}
/* initialize UDP header */
out->tf_udp.uh_sport = (millitime() & 1023) + 1024;/* source post */
out->tf_udp.uh_dport = IPPORT_TFTP; /* destination port */
out->tf_udp.uh_sum = 0; /* no checksum */
/* set tftpglob structure */
tf->tf_block = 1;
tf->tf_data = (char *)KERNEL_START;
/* Create the TFTP Read Request
* packet */
out->tf_tftp.th_opcode = RRQ;
/* load internet address */
q = bp->bp_name;
p = out->tf_tftp.th_stuff;
while (*q && *q != ' ') {
*(p++) = *(q++);
}
*p++ = 0;
q = "octet";
while (*p++ = *q++)
;
/* fill UDP packet */
out->tf_udp.uh_ulen = sizeof (struct udphdr) + 2 +
(p - out->tf_tftp.th_stuff);
/* fill ip packet */
out->tf_ip.ip_len = sizeof (struct ip) + out->tf_udp.uh_ulen;
/* init. transmit status */
locked = 0;
retry = 0;
time = millitime();
/* transmit loop */
for (xcount = 0; xcount < 5;) { /* try to xmit 5 times */
if (millitime() >= time) {
time = millitime() + delay;
/* limit delay to 64 sec */
delay = delay < 64000 ? delay * 2 : 64000;
/* show activity */
printf("%c\b", ind[feedback++ % 4]);
/* transmit */
if (ip_output(sip,
((caddr_t)out) - sizeof (struct ether_header) ,
out->tf_ip.ip_len + sizeof (struct ether_header),
&tf->tf_inet, tf->tf_tmpbuf))
printf("X\b");
/* 5 times if not locked */
if (locked == 0 || retry > 15)
xcount++;
else
retry++;
}
/* get input IP packet */
len = ip_input(sip,((caddr_t)in) - sizeof(struct ether_header),
&tf->tf_inet);
/* check length of packet */
if (len < TFTPHDRLEN) {
#ifdef debugjl
/*printf(" not tftp packet\n");*/
#endif debugjl
continue;
}
/* check packet type */
if (in->tf_ip.ip_p != IPPROTO_UDP ||
in->tf_udp.uh_dport != out->tf_udp.uh_sport) {
#ifdef debugjl
printf(" wrong packet type = %x\n",in->tf_ip.ip_p);
#endif debugjl
continue;
}
/* dst has been locked in */
#ifdef SUN4
if ( locked &&
( (out->tf_ip.ip_dst.S_un.S_un_b.s_b1 !=
in->tf_ip.ip_src.S_un.S_un_b.s_b1) ||
(out->tf_ip.ip_dst.S_un.S_un_b.s_b2 !=
in->tf_ip.ip_src.S_un.S_un_b.s_b2) ||
(out->tf_ip.ip_dst.S_un.S_un_b.s_b3 !=
in->tf_ip.ip_src.S_un.S_un_b.s_b3) ||
(out->tf_ip.ip_dst.S_un.S_un_b.s_b4 !=
in->tf_ip.ip_src.S_un.S_un_b.s_b4)) )
#else SUN4
if (locked &&
out->tf_ip.ip_dst.s_addr != in->tf_ip.ip_src.s_addr)
#endif SUN4
#ifdef debugjl
{
printf(" not locked address = %x%x%x%x\n",
out->tf_ip.ip_dst.S_un.S_un_b.s_b1,
out->tf_ip.ip_dst.S_un.S_un_b.s_b2,
out->tf_ip.ip_dst.S_un.S_un_b.s_b3,
out->tf_ip.ip_dst.S_un.S_un_b.s_b4);
continue;
}
#else
continue;
#endif debugjl
/* error */
if (in->tf_tftp.th_opcode == ERROR) {
if (autoboot && tf->tf_block == 1)
continue;
if (in->tf_tftp.th_code < 0 ||
in->tf_tftp.th_code > sizeof(tftp_errs)/sizeof(char *)){
printf("tftp: Unknown error 0x%x\n",
in->tf_tftp.th_code);
} else {
printf("tftp: %s @ block %d\n",
tftp_errs[in->tf_tftp.th_code], tf->tf_block);
}
/* for autoboot, keep looping */
if (autoboot)
goto top;
return (-1);
}
/* we are looking for data */
if (in->tf_tftp.th_opcode != DATA ||
in->tf_tftp.th_block != tf->tf_block)
#ifdef debugjl
{
printf(" not data packet");
continue;
}
#else
continue;
#endif debugjl
/* in sequence DATA packet */
if (tf->tf_block == 1) {
/* lock onto server port */
out->tf_udp.uh_dport = in->tf_udp.uh_sport;
/* for autoboot, get address */
if (autoboot)
bcopy(&(in->tf_ip.ip_src),&(out->tf_ip.ip_dst),
sizeof(in->tf_ip.ip_src));
/* print server found */
printf("Booting from tftp server at ");
inet_print(out->tf_ip.ip_dst);
locked = 1;
}
/* calc. data length */
len = in->tf_udp.uh_ulen - (sizeof(struct udphdr) + 4);
/* copy data to load point */
if (len) {
bcopy(in->tf_tftp.th_data, tf->tf_data, len);
if (tf->tf_block == 1) {
header = (struct exec *)tf->tf_data;
printf("Size: %d", header->a_text);
}
tf->tf_data += len;
if (header->a_text) {
header->a_text -= len;
if (tf->tf_block == 1) {
/*
* If on first block, don't count header size against the
* text size.
*/
header->a_text += sizeof(struct exec);
}
if ((int)header->a_text <= 0) {
printf("+%d", header->a_data);
header->a_data += header->a_text;
header->a_text = 0;
}
} else {
header->a_data -= len;
if ((int)header->a_data <= 0) {
printf("+%d\n", header->a_bss);
finished = 1;
}
}
}
/* send ACK (acknowledge) */
out->tf_tftp.th_opcode = ACK;
out->tf_tftp.th_block = tf->tf_block++;
out->tf_udp.uh_ulen = sizeof (struct udphdr) + 4;
out->tf_ip.ip_len = sizeof (struct ip) + out->tf_udp.uh_ulen;
/* transmit */
if (ip_output(sip, (caddr_t)out - sizeof(struct ether_header),
out->tf_ip.ip_len +
sizeof (struct ether_header), &tf->tf_inet,
tf->tf_tmpbuf))
printf("X\b");
/* reset count and retry */
xcount = 0;
retry = 0;
printf("%c\b", ind[feedback++ % 4]); /* Show activity */
/* reset delay */
delay = REXMIT_MSEC;
time = millitime()+delay;
/* check if end of file */
if ((len < SEGSIZE) || finished) {
#ifndef sun4
/*
* Zero out the uninitialized data, since Sprite
* doesn't do it for
* itself...
*/
tf->tf_data += (int)header->a_data;
bzero(tf->tf_data, header->a_bss);
#endif
printf("Downloaded %d bytes from tftp server.\n\n",
tf->tf_data - KERNEL_START);
return (KERNEL_START + sizeof(struct exec));
}
}
printf("tftp: time-out.\n");
/* for autoboot, loop forever */
if (autoboot)
goto top;
/* error return */
return (-1);
}